home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / network / ncsasock / sock_udp.c < prev    next >
Text File  |  1996-07-05  |  9KB  |  431 lines

  1. /*
  2.  * BSD-style socket emulation library for the Mac
  3.  * Original author: Tom Milligan
  4.  * Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
  5.  *
  6.  * This source file is placed in the public domian.
  7.  * Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
  8.  *
  9.  *      National Center for Supercomputing Applications
  10.  *      152 Computing Applications Building
  11.  *      605 E. Springfield Ave.
  12.  *      Champaign, IL  61820
  13.  */
  14.  
  15. #ifdef USEDUMP
  16. # pragma load "Socket.dump"
  17.  
  18. #else
  19. # include <Events.h>
  20. # include <Memory.h>
  21. # include <Errors.h>
  22. # include <Types.h>
  23. # include <OSUtils.h>
  24. # include <Stdio.h>
  25.  
  26. # include <s_types.h>
  27. # include <neti_in.h>
  28. # include <neterrno.h>
  29. # include <s_socket.h>
  30. # include <s_time.h>
  31. # include <s_uio.h>
  32.  
  33. # include "sock_str.h"
  34. # include "sock_int.h"
  35.  
  36. #endif
  37.  
  38. extern SocketPtr sockets;
  39. extern SpinFn spinroutine;
  40.  
  41. #if 0
  42. /*
  43.  * asynchronous notification routine 
  44.  */
  45. static int notified = 0;
  46. static int lastNotifyCount = 0;
  47.  
  48. static StreamPtr notifyUdpStream;
  49. static unsigned short notifyEventCode;
  50. static Ptr notifyUserDataPtr;
  51. static unsigned short notifyTerminReason;
  52. static struct ICMPReport *notifyIcmpMsg;
  53.  
  54. pascal void sock_udp_notify(
  55.     StreamPtr udpStream,
  56.     unsigned short eventCode,
  57.     Ptr userDataPtr,
  58.     struct ICMPReport *icmpMsg)
  59. {
  60.     notified++;
  61.  
  62.     notifyUdpStream = udpStream;
  63.     notifyEventCode = eventCode;
  64.     notifyUserDataPtr = userDataPtr;
  65.     notifyIcmpMsg = icmpMsg;
  66. }
  67.  
  68. static char *eventNames[] = 
  69. {
  70.     "event 0",
  71.     "data arrival",
  72.     "ICMP message"
  73. };
  74. static char *icmpMessages[] =
  75. {
  76.     "net unreachable",
  77.     "host unreachable",
  78.     "protocol unreachable",
  79.     "port unreachable",
  80.     "fragmentation required",
  81.     "source route failed",
  82.     "time exceeded",
  83.     "parameter problem",
  84.     "missing required option"
  85. };
  86.  
  87.  
  88. int udpCheckNotify()
  89. {
  90.     if (notified == lastNotifyCount)
  91.         return(0);
  92.     
  93.     lastNotifyCount = notified;
  94.     dprintf("notify count is now %d\n",lastNotifyCount);
  95.     dprintf("stream %08x\n",notifyUdpStream);
  96.     dprintf("event %d '%s'\n",notifyEventCode,eventNames[notifyEventCode]);
  97.     if (notifyEventCode == UDPDataArrival)
  98.         dprintf("%d bytes\n",notifyTerminReason/*!?*/);
  99.     dprintf("icmp msg %08x\n",notifyIcmpMsg);
  100.     if (notifyEventCode == UDPICMPReceived)
  101.     {
  102.         dprintf("stream %08x\n",notifyIcmpMsg->streamPtr);
  103.         dprintf("local %08x/%d\n",notifyIcmpMsg->localHost,notifyIcmpMsg->localPort);
  104.         dprintf("remote %08x/%d\n",notifyIcmpMsg->remoteHost,notifyIcmpMsg->remotePort);
  105.         dprintf("%s\n",icmpMessages[notifyIcmpMsg->reportType]);
  106.         dprintf("optionalAddlInfo %04x\n",notifyIcmpMsg->optionalAddlInfo);
  107.         dprintf("optionalAddlInfoPtr %08x\n",notifyIcmpMsg->optionalAddlInfoPtr);
  108.     }
  109.     dprintf("userdata %s\n",notifyUserDataPtr);
  110.     return(1);
  111. }
  112.  
  113. #endif
  114.  
  115.  
  116. static int sock_udp_read_ahead(SocketPtr sp);
  117.  
  118. /*
  119.  * sock_udp_new_stream()  - create the MacTCP stream for this socket. not
  120.  *                          called till the last minute while we wait for
  121.  *                          a bind to come in.
  122.  *
  123.  *                          called from whichever of connect, recv, send or 
  124.  *                          select (can_recv or can_send) is called first.
  125.  */
  126. int sock_udp_new_stream(
  127.     SocketPtr sp)
  128. {
  129. OSErr                 io;
  130. StreamHashEntPtr     shep;
  131.     
  132. #if SOCK_UDP_DEBUG >= 2
  133.     dprintf("sock_udp_new_stream: sp %08x port %d\n", sp, sp->sa.sin_port);
  134. #endif
  135.     
  136.     if ( (io=xUDPCreate(sp, STREAM_BUFFER_SIZE, sp->sa.sin_port)) != noErr )
  137.         return(sock_err(io));
  138.         
  139.     sp->sstate = SOCK_STATE_UNCONNECTED;
  140.     
  141.     if ((shep = sock_new_shep(sp->stream)) != NULL)
  142.         {
  143.         shep -> stream = sp->stream;
  144.         shep -> socket = sp;
  145.         }
  146.     else
  147.         return -1;
  148.         
  149.     sp-> recvd = 0;
  150.     sp-> recvBuf = 0;
  151.     sp-> asyncerr = inProgress;
  152.     
  153.     /* start up the read ahead */
  154.     return(sock_udp_read_ahead(sp));
  155. }
  156.  
  157.  
  158. /*
  159.  *    sock_udp_connect() - sets the peer process we will be talking to
  160.  */
  161. int sock_udp_connect(
  162.     SocketPtr sp,
  163.     struct sockaddr_in *addr)
  164. {
  165.     int status;
  166.     
  167.     /* make the stream if its not made already */
  168.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  169.     {
  170.         status = sock_udp_new_stream(sp);
  171.         if (status != 0)
  172.             return(status);
  173.     }
  174.     
  175.     /* record our peer */
  176.     sp->peer.sin_len = sizeof(struct sockaddr_in);
  177.     sp->peer.sin_addr.s_addr = addr->sin_addr.s_addr;
  178.     sp->peer.sin_port = addr->sin_port;
  179.     sp->peer.sin_family = AF_INET;
  180.     sp->sstate = SOCK_STATE_CONNECTED;
  181.     
  182.     if (sp-> recvBuf) {
  183.         xUDPBfrReturn(sp);
  184.         }
  185.     /* flush the read-ahead buffer if its not from our new friend */
  186.     (void) sock_udp_can_recv(sp);
  187.     
  188.     return(0);
  189. }
  190.  
  191.  
  192. static void sock_udp_read_ahead_done(UDPiopb *pb);
  193.  
  194. /*
  195.  * sock_udp_read_ahead() - start up the one packet read-ahead
  196.  *
  197.  *                         called from new_stream, recv and can_recv
  198.  */
  199. static int sock_udp_read_ahead(SocketPtr sp)
  200.     {
  201.     OSErr io;
  202.     
  203.     io = xUDPRead(sp, (UDPIOCompletionProc)sock_udp_read_ahead_done);
  204.     if (io != noErr) 
  205.         return(sock_err(io));
  206.  
  207.     return(0);
  208.     }
  209.  
  210. /*
  211.  * sock_udp_return_buffer() - return the receive buffer to MacTCP
  212.  */
  213. static 
  214. int sock_udp_return_buffer(
  215.     SocketPtr sp)
  216. {
  217.     OSErr io;
  218.     
  219.     if (sp->recvBuf)
  220.     {
  221.         io = xUDPBfrReturn(sp);
  222.         if (io != noErr)
  223.             return(sock_err(io));
  224.     }
  225.     return(noErr);
  226. }
  227.  
  228. /*
  229.  * sock_udp_recv()
  230.  *
  231.  * returns bytes received or -1 and errno
  232.  */
  233. int sock_udp_recv(
  234.     SocketPtr sp,
  235.     char *buffer,
  236.     int buflen,
  237.     int flags,
  238.     struct sockaddr_in *from,
  239.     int *fromlen)
  240. {
  241. #pragma unused(flags)
  242.     
  243. #if SOCK_UDP_DEBUG >= 2
  244.     dprintf("sock_udp_recv: sp %08x buflen %d state %04x\n", sp,buflen,sp->sstate);
  245. #endif
  246.  
  247.     /* make the stream if its not made already */
  248.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  249.     {
  250.         int status = sock_udp_new_stream(sp);
  251.         if (status != 0)
  252.             return(status);
  253.     }
  254.     
  255.     /* dont block a non-blocking socket */
  256.     if (sp->nonblocking && !sock_udp_can_recv(sp))
  257.         return(sock_err(EWOULDBLOCK));
  258.     
  259.     SPIN(!sock_udp_can_recv(sp),SP_UDP_READ,0)
  260.  
  261.     if (sp->asyncerr!=noErr)
  262.         return(sock_err(sp->asyncerr));
  263.  
  264.     /* return the data to the user - truncate the packet if necessary */
  265.     buflen = min(buflen,sp->recvd);    
  266.     BlockMove(sp->recvBuf,buffer,buflen);
  267.     
  268. #if (SOCK_UDP_DEBUG >= 7) || defined(UDP_PACKET_TRACE)
  269. /*
  270.     hex_dump(buffer, buflen, "udp from %08x/%d\n",
  271.             sp->apb.pb.udp.csParam.receive.remoteHost,
  272.             sp->apb.pb.udp.csParam.receive.remotePort);
  273. */
  274. #endif
  275.  
  276.     if (from != NULL && *fromlen >= sizeof(struct sockaddr_in))
  277.         {
  278.         (*from) = sp->peer;
  279.         (*fromlen) = sizeof (struct sockaddr_in);
  280.         }    
  281.     
  282.     /* continue the read-ahead - errors which occur */
  283.     /* here will show up next time around */
  284.     (void) sock_udp_return_buffer(sp);
  285.     (void) sock_udp_read_ahead(sp);
  286.  
  287.     return(buflen);
  288. }
  289.  
  290.  
  291. /*
  292.  *    sock_udp_can_recv() - returns non-zero if a packet has arrived.
  293.  *
  294.  *                        Used by select, connect and recv.
  295.  */
  296. int sock_udp_can_recv(SocketPtr sp)
  297.     {
  298.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  299.         {
  300.         int status = sock_udp_new_stream(sp);
  301.         if (status != 0)
  302.             return(-1);
  303.         }
  304.     
  305.     if (sp->asyncerr == inProgress)
  306.         return(0);
  307.     
  308.     return 1;  // must recieve if not reading, even if an error occured - must handle error.
  309.     }
  310.  
  311.  
  312. static void sock_udp_send_done(UDPiopb *pb);
  313.  
  314. /*
  315.  *    sock_udp_send() - send the data in the (already prepared) wds
  316.  *
  317.  *    returns bytes sent or -1 and errno
  318.  */
  319. int sock_udp_send(SocketPtr sp,struct sockaddr_in *to,char *buffer,int count,int flags)
  320.     {
  321. #pragma unused(flags)
  322.     miniwds  awds;
  323.     OSErr    io;
  324.     
  325. #if SOCK_UDP_DEBUG >= 2
  326.     dprintf("sock_udp_send: %08x state %04x\n",sp,sp->sstate);
  327. #endif
  328.  
  329.     /* make the stream if its not made already */
  330.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  331.         {
  332.         io = sock_udp_new_stream(sp);
  333.         if (io != 0)
  334.             return(io);
  335.         }
  336.     
  337.     if ( count > UDP_MAX_MSG )
  338.         return sock_err(EMSGSIZE);
  339.         
  340.     awds.terminus = 0;
  341.     awds.length = count;
  342.     awds.ptr = buffer;
  343.     
  344.     // if no address passed, hope we have one already in peer field
  345.     if (to == NULL)
  346.         if (sp->peer.sin_len)
  347.             to = &sp->peer;
  348.         else
  349.             return (sock_err(EHOSTUNREACH));
  350.     
  351.     io = xUDPWrite(sp, to->sin_addr.s_addr,to->sin_port, &awds, 
  352.             (UDPIOCompletionProc)sock_udp_send_done);
  353.     
  354.     if (io != noErr )
  355.         return(io);
  356.     
  357.     // get sneaky. compl. proc sets ptr to nil on completion, and puts result code in
  358.     // terminus field.
  359.     
  360.     SPIN(awds.ptr != NULL,SP_UDP_WRITE,count)
  361.     return (awds.terminus);
  362.     }
  363.  
  364. /*
  365.  *    sock_udp_can_send() - returns non-zero if a write will not block
  366.  */
  367. int sock_udp_can_send(SocketPtr sp)
  368.     {
  369.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  370.         {
  371.         if ( sock_udp_new_stream(sp) != 0 )
  372.             return(-1);
  373.         }
  374.     
  375.     return (1);
  376.     }
  377.  
  378. /*
  379.  *    sock_udp_close()
  380.  */
  381. int sock_udp_close(SocketPtr sp)
  382.     {
  383.     OSErr io;
  384.     
  385.     if (sp->sstate == SOCK_STATE_NO_STREAM)
  386.         return(0);
  387.     io = xUDPRelease(sp);
  388.     if (io != noErr)
  389.         return(sock_err(io));
  390.     return(0);
  391.     }
  392.     
  393. #ifndef COMP_CODEWAR
  394. #pragma segment SOCK_RESIDENT
  395. #endif
  396. /*
  397.  * Interrupt routines - MUST BE IN A RESIDENT SEGMENT! Most important to 
  398.  * MacApp programmers
  399.  */
  400.     
  401.     
  402. /*
  403.  * sock_udp_send_done
  404.  */
  405.  
  406. static void sock_udp_send_done(UDPiopb *pb) 
  407. {
  408.     ((miniwds *)pb->csParam.send.wdsPtr)->terminus = pb->ioResult;
  409.     ((miniwds *)pb->csParam.send.wdsPtr)->ptr = NULL;
  410.     }
  411.  
  412. /*
  413.  * sock_udp_read_ahead_done
  414.  */
  415. static void sock_udp_read_ahead_done(UDPiopb *pb) 
  416. {
  417.     register    SocketPtr    sp;
  418.     
  419.     sp = sock_find_shep( pb->udpStream )->socket;
  420.     if (pb->ioResult == noErr) {
  421.         sp->recvBuf = pb->csParam.receive.rcvBuff;
  422.         sp->recvd   = pb->csParam.receive.rcvBuffLen;
  423.         }
  424.     else {
  425.         sp-> recvd = 0;
  426.         sp-> recvBuf = 0;
  427.         }
  428.     sp->asyncerr = pb->ioResult;
  429.     }
  430.  
  431.